#include "my_http.h"


static const char *TAG = "MY_HTTP";

my_http_cb_t g_user_cb;
httpd_handle_t server = NULL;

esp_err_t my_http_event_handler(esp_http_client_event_t *evt)
{
	// static char *output_buffer;  // Buffer to store response of http request from event handler
	static int output_len;       // Stores number of bytes read
	switch(evt->event_id) {
		case HTTP_EVENT_ERROR:
			ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
			break;
		case HTTP_EVENT_ON_CONNECTED:
			ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
			break;
		case HTTP_EVENT_HEADER_SENT:
			ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
			break;
		case HTTP_EVENT_ON_HEADER:
			ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
			break;
		case HTTP_EVENT_ON_DATA:
			ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
			/*
			 *  Check for chunked encoding is added as the URL for chunked encoding used in this example returns binary data.
			 *  However, event handler can also be used in case chunked encoding is used.
			 */
			if (!esp_http_client_is_chunked_response(evt->client)) {
				// If user_data buffer is configured, copy the response into the buffer
				if (evt->user_data) {
					memcpy(evt->user_data + output_len, evt->data, evt->data_len);
				} 
				// else {
				//     if (output_buffer == NULL) {
				//         output_buffer = (char *) malloc(esp_http_client_get_content_length(evt->client));
				//         output_len = 0;
				//         if (output_buffer == NULL) {
				//             ESP_LOGE(TAG, "Failed to allocate memory for output buffer, len:%d", esp_http_client_get_content_length(evt->client));
				//             return ESP_FAIL;
				//         }
				//     }
				//     memcpy(output_buffer + output_len, evt->data, evt->data_len);
				// }
				output_len += evt->data_len;
			}

			break;
		case HTTP_EVENT_ON_FINISH:
			ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
			// if (output_buffer != NULL) {
			//     // Response is accumulated in output_buffer. Uncomment the below line to print the accumulated response
			//     // ESP_LOG_BUFFER_HEX(TAG, output_buffer, output_len);
			//     free(output_buffer);
			//     output_buffer = NULL;
			// }
			output_len = 0;
			break;
		case HTTP_EVENT_DISCONNECTED:
			ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
			int mbedtls_err = 0;
			esp_err_t err = esp_tls_get_and_clear_last_error(evt->data, &mbedtls_err, NULL);
			if (err != 0) {
				ESP_LOGI(TAG, "Last esp error code: 0x%x", err);
				ESP_LOGI(TAG, "Last mbedtls failure: 0x%x", mbedtls_err);
			}
			// if (output_buffer != NULL) {
			//     free(output_buffer);
			//     output_buffer = NULL;
			// }
			output_len = 0;
			break;
	}
	return ESP_OK;
}

static esp_err_t my_get_handler(httpd_req_t *req)
{
	if (g_user_cb.get_cb) {
		g_user_cb.get_cb(req);
	}
	return ESP_OK;
}

/* Our URI handler function to be called during POST /uri request */
static esp_err_t my_post_handler(httpd_req_t *req)
{
	char content[256];
	size_t recv_size = MIN(req->content_len, sizeof(content));

	int ret = httpd_req_recv(req, content, recv_size);
	if (ret <= 0) {
		if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
			httpd_resp_send_408(req);
		}
		return ESP_FAIL;
	}

	memset(content + recv_size, 0, 1);
	// printf("===post recv : %d\n", recv_size);
	// printf("%s", content);
	// printf("\n===end\n");

	if (g_user_cb.post_cb) {
		g_user_cb.post_cb(req, content, recv_size);
	}
	return ESP_OK;
}

// static esp_err_t my_http_404_error_handler(httpd_req_t *req, httpd_err_code_t err)
// {
// 	ESP_LOGE(TAG, "my_http_404_error_handler: 404 Error");
// 	/* For any other URI send 404 and close socket */
// 	httpd_resp_send_err(req, HTTPD_404_NOT_FOUND);
// 	return ESP_FAIL;
// }

/* URI handler structure for GET /uri */
httpd_uri_t g_web_index = {
	.uri      = "/",
	.method   = HTTP_GET,
	.handler  = my_get_handler,
	.user_ctx = NULL
};

/* URI handler structure for POST /uri */
httpd_uri_t g_uri_post = {
	.uri      = "/set",
	.method   = HTTP_POST,
	.handler  = my_post_handler,
	.user_ctx = NULL
};


int my_http_server_set_callback(my_http_cb_t user_cb)
{
	g_user_cb.get_cb = user_cb.get_cb;
	g_user_cb.post_cb = user_cb.post_cb;

	return 0;
}


httpd_handle_t my_start_webserver(void)
{
	if (server != NULL) {
		return 0;
	}

	httpd_config_t config = HTTPD_DEFAULT_CONFIG();
	config.lru_purge_enable = true;

	// Start the httpd server
	ESP_LOGW(TAG, "Starting server on port: '%d'", config.server_port);
	if (httpd_start(&server, &config) == ESP_OK) {
		ESP_LOGI(TAG, "Registering URI handlers");
		httpd_register_uri_handler(server, &g_web_index);
		httpd_register_uri_handler(server, &g_uri_post);
		// httpd_register_err_handler(server, HTTPD_404_NOT_FOUND, my_http_404_error_handler);

		return server;
	}

	ESP_LOGI(TAG, "Error starting server!");
	return NULL;
}

void my_stop_webserver(httpd_handle_t server)
{
	ESP_LOGW(TAG, "stop webserver");
	httpd_stop(server);
}

int start_ota(const char *url)
{   
	esp_http_client_config_t config = {
		.url = url,
		.event_handler = my_http_event_handler,
	};

	ESP_LOGW(TAG, "start ota ....");
	esp_err_t ret = esp_https_ota(&config);
	if (ret == ESP_OK) {
		esp_restart();
	} else {
		ESP_LOGE(TAG, "Firmware Upgrades Failed");
	}
	return -1;
}

int http_client_GET(esp_http_client_config_t *config)
{
	int rec_len = 0;

	if (config->event_handler == NULL) {
		config->event_handler = my_http_event_handler;
	}
	
	esp_http_client_handle_t client = esp_http_client_init(config);
	esp_err_t err = esp_http_client_perform(client);
	if (err == ESP_OK) {
		rec_len = esp_http_client_get_content_length(client);
		ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %d",
				esp_http_client_get_status_code(client),
				rec_len);
	} else {
		ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
		rec_len = -1;
	}
	esp_http_client_cleanup(client);
	return rec_len;
}

int http_client_GET_test(void)
{
	int recv = 0;
	char *buf = malloc(512);
	memset(buf, 0, 512);
	esp_http_client_config_t config = {
		.method = HTTP_METHOD_GET,
		.url = "http://v1.hitokoto.cn/?c=f&encode=text",
		.user_data = buf,
		.disable_auto_redirect = true,
	};
	recv = http_client_GET(&config);

	if (recv > 0) {
		printf("\nGET %d Byte:\n%s\n\n", recv, buf);
	} else {
		ESP_LOGE(TAG, "http_client_GET Error, recv:%d\n\n", recv);
		return -1;
	}

	if (buf != NULL) {
		free(buf);
		buf = NULL;
	}
	return 0;
}
